package com.helloandroid.paso.ui.mediaplayer;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MPlayer {
	
	private Context ctx;
	private MediaPlayer mediaPlayer;
	private int trackSelectDlgID, pauseBtnID, playBtnID, dlgItemID, dlgListViewID, titleTextID;
	private TextView infoText;
	private ImageButton playPauseButton, nextButton, trackListButton;
	private ProgressBar pBar;
	
	final Handler handler = new Handler();
	
	private enum PlayPauseState {PLAY, PAUSE};
	private PlayPauseState currPlayPauseState;
	
	private boolean isPaused, playbackStarted;
	private Playlist playlist;

	public void InitMPlayer(Context context, TextView tView,
			ImageButton playPauseButton, ImageButton nextButton,
			ImageButton trackListButton, ProgressBar trackProgressBar,
			int trackSelectDialogID, int pauseButtonID,
			int playButtonID, int dialogItemID, int dialogListViewID, int trackTitleTextID) {
		
		ctx = context;
		infoText = tView;
		this.playPauseButton = playPauseButton;
		this.nextButton = nextButton;
		this.trackListButton = trackListButton;
		
		// Disable buttons, they'll be re-enabled when the playlist successfully loads
		changeButtonState(false);
		
		pBar = trackProgressBar;
		trackSelectDlgID = trackSelectDialogID;
		pauseBtnID = pauseButtonID;
		playBtnID = playButtonID;
		dlgItemID = dialogItemID;
		dlgListViewID = dialogListViewID;
		titleTextID = trackTitleTextID;
		playlist = new Playlist();
		
		setListeners();	
	}
		
	private void setListeners(){
		
		playPauseButton.setOnClickListener(playButtonClick);
		
		nextButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				playlist.next();
				isPaused = false;
				
				if(playbackStarted)
					play(playlist.getCurrentTrack());
			}
		});		

		trackListButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				TrackSelectDialog trackSelectDialog = new TrackSelectDialog(ctx);

				// Show the dialog
				trackSelectDialog.selectTrack(playlist.getPlaylist(), trackSelectDlgID, dlgItemID, dlgListViewID, titleTextID,
						new ISelectDialogCallback() {

							// Change current track and play it
							@Override
							public void onTrackSelect(Track track) {
								playlist.setCurrentTrack(track);
								isPaused = false;
								play(track);
							}
						}); 
			}
		});
		
		playlist.setPlaylistStatusListener(new IPlaylistStatusListener() {
			
			// Enable buttons if the playlist successfully loaded
			@Override
			public void onSuccessfulPlaylistLoad() {
				changeButtonState(true);
			}
			
			// Show message that the playlist could not be loaded
			@Override
			public void onFailedPlaylistLoad() {
				infoText.setText("Failed to load playlist");
			}

			@Override
			public void onTrackChange(Track newTrack) {
				if(newTrack.tag == null){
					infoText.setText(Helper.getFilenameFromURL(newTrack.path));
				}
				else if(TextUtils.isEmpty(newTrack.tag.Title)){
					infoText.setText(Helper.getFilenameFromURL(newTrack.path));
				}
				else{
					infoText.setText(newTrack.tag.Title);
				}
			}
		});
	}
	
	private void play(Track track){
		playbackStarted = true;
		
		if(mediaPlayer == null){
			mediaPlayer = new MediaPlayer();
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
		}
		
		if(isPaused){
			isPaused = false;
			setPlayPauseState(PlayPauseState.PAUSE);
			mediaPlayer.start();
			startPlayProgressUpdater();
		}
		
		else{
			mediaPlayer.reset();
			try {
				mediaPlayer.setDataSource(track.path);
			} catch (IllegalArgumentException e) {
				infoText.setText("Cannot start playback");
			} catch (IllegalStateException e) {
				infoText.setText("Cannot start playback");
			} catch (IOException e) {
				infoText.setText("Cannot start playback");
			}
			
			final CharSequence oldInfoText = infoText.getText();
			infoText.setText("Preparing...");
			mediaPlayer.prepareAsync();
			
			playPauseButton.setEnabled(false);
			
			mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
				
				@Override
				public void onPrepared(MediaPlayer mp) {
					mp.start();
					startPlayProgressUpdater();
					infoText.setText(oldInfoText);
					playPauseButton.setEnabled(true);
					setPlayPauseState(PlayPauseState.PAUSE);
				}
			});
			
			mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
				
				@Override
				public void onCompletion(MediaPlayer mp) {
					pBar.setProgress(0);
					setPlayPauseState(PlayPauseState.PLAY);
					playbackStarted = false;
				}
			});
		}
	}
	
	private OnClickListener playButtonClick = new OnClickListener() {

		@Override
		public void onClick(View v) {
			play(playlist.getCurrentTrack());
		}
	};

	private OnClickListener pauseButtonClick = new OnClickListener() {

		@Override
		public void onClick(View v) {
			pause();
		}
	};
	
	private void pause(){
		if (mediaPlayer != null) {
			isPaused = true;
			mediaPlayer.pause();
			setPlayPauseState(PlayPauseState.PLAY);
		}
	}
	
	private void setPlayPauseState(PlayPauseState state) {
		if(currPlayPauseState == state)
			return;
		
		switch (state) {
		case PAUSE:
			playPauseButton.setBackgroundResource(pauseBtnID);
			playPauseButton.setOnClickListener(pauseButtonClick);
			currPlayPauseState = PlayPauseState.PAUSE;
			break;
			
		case PLAY:
			playPauseButton.setBackgroundResource(playBtnID);
			playPauseButton.setOnClickListener(playButtonClick);
			currPlayPauseState = PlayPauseState.PLAY;
			break;
		}
	}
	
	/**
	 * Method to stop and release the player when it's no longer needed (e.g. on application exit)
	 */
	public void dispose(){
		if(mediaPlayer != null){
			mediaPlayer.stop();
			mediaPlayer.release();
		}
	}
	
	private void startPlayProgressUpdater() {
		if(mediaPlayer == null)
			return;
		
		// Only try to request information from the player when it's actually playing something
		if (mediaPlayer.isPlaying()) {
	    	float progress = (((float)mediaPlayer.getCurrentPosition()) / mediaPlayer.getDuration());
	    	pBar.setProgress((int)(progress * 100));    	
			
				Runnable notification = new Runnable() {
			        public void run() {
			        	startPlayProgressUpdater();
					}
			    };
			    
			    // Run this method again after 1 second
			    handler.postDelayed(notification, 1000);
    	}
    }
	
	// Enable/disable buttons
	private void changeButtonState(boolean isEnabled){
		playPauseButton.setEnabled(isEnabled);
		nextButton.setEnabled(isEnabled);
		trackListButton.setEnabled(isEnabled);
	}
	
	// Methods to set the playlist
	public void setPlaylist(File M3UFile){
		playlist.setPlaylist(M3UFile);
	}
	
	public void setPlaylist(URL M3UFileURL){
		playlist.setPlaylist(M3UFileURL);
	}
	
	public void setPlaylist(String[] trackPaths){
		playlist.setPlaylist(trackPaths);
	}
}
